#ifndef DW_SYSTEM_SERIALIZER_H
#	define DW_SYSTEM_SERIALIZER_H

namespace std 
{  

template< typename T >
struct iterator_traits< std::back_insert_iterator< T > > 
{
	typedef typename T::iterator Iterator;
	typedef typename Iterator::difference_type difference_type;
	typedef typename Iterator::value_type value_type;
	typedef typename Iterator::pointer pointer;
	typedef typename Iterator::reference reference;
	typedef typename Iterator::iterator_category iterator_category;
};

template< typename T >
struct iterator_traits< std::insert_iterator< T > >
{
	typedef typename T::iterator Iterator;
	typedef typename Iterator::difference_type difference_type;
	typedef typename Iterator::value_type value_type;
	typedef typename Iterator::pointer pointer;
	typedef typename Iterator::reference reference;
	typedef typename Iterator::iterator_category iterator_category;
};

} // namespace std

namespace dw {
	namespace system {

class ISerializable;

class ISerializer
{
public : //! @name Commands
	//! @{
	virtual void Serialize() = 0;
	virtual void Serialize(const ISerializable& obj) = 0;
	virtual void Deserialize(ISerializable& obj) = 0;
	//! @}
};

class Serializer
:	public ISerializer
{
public : //! @name Construction & destruction
	//! @{
	inline Serializer(std::iostream* stream);
	inline Serializer(std::ostream* os, std::istream* is);
	//! @}

	/// Primitive type
	inline void Serialize(const bool data);
	inline void Serialize(const char data);
	inline void Serialize(const unsigned char data);
	inline void Serialize(const short data);
	inline void Serialize(const unsigned short data);
	inline void Serialize(const int data);
	inline void Serialize(const unsigned int data);
	inline void Serialize(const float data);
	inline void Serialize(const double data);


	/// Commmon STL containers
	template< typename InputIterator >
	inline void SerializeRange(const InputIterator& begin, const InputIterator& end, const size_t size);
	template< typename InputIterator >
	inline void SerializeRange(const InputIterator& begin, const InputIterator& end);
	template< typename T1, typename T2 >
	inline void Serialize(const std::pair< T1, T2 >& obj);
	template< typename T >
	inline void Serialize(const std::vector< T >& obj);
	template< typename T >
	inline void Serialize(const std::list< T >& obj);
	template< typename Key, typename Compare >
	inline void Serialize(const std::set< Key, Compare >& obj);
	template< typename Key, typename Compare >
	inline void Serialize(const std::multiset< Key, Compare >& obj);
	template< typename Key, typename Data, typename Compare >
	inline void Serialize(const std::map< Key, Data, Compare >& obj);
	template< typename Key, typename Data, typename Compare >
	inline void Serialize(const std::multimap< Key, Data, Compare >& obj);
	inline void Serialize(const std::string& obj);

	/// Custom type
	inline void Serialize(const ISerializable& obj);

	/// Pointer type
	template< typename T >
	inline void Serialize(const T* dataPtr);

	/// Primitive type
	inline void Deserialize(bool& data);
	inline void Deserialize(char& data);
	inline void Deserialize(unsigned char& data);
	inline void Deserialize(short& data);
	inline void Deserialize(unsigned short& data);
	inline void Deserialize(int& data);
	inline void Deserialize(unsigned int& data);
	inline void Deserialize(float& data);
	inline void Deserialize(double& data);

	/// Commmon STL containers
	template< typename OutputIterator >
	inline void DeserializeRange(OutputIterator it);
	template< typename T1, typename T2 >
	inline void Deserialize(std::pair< T1, T2 >& obj);
	template< typename T >
	inline void Deserialize(std::vector< T >& obj);
	template< typename T >
	inline void Deserialize(std::list< T >& obj);
	template< typename Key, typename Compare >
	inline void Deserialize(std::set< Key, Compare >& obj);
	template< typename Key, typename Compare >
	inline void Deserialize(std::multiset< Key, Compare >& obj);
	template< typename Key, typename Data, typename Compare >
	inline void Deserialize(std::map< Key, Data, Compare >& obj);
	template< typename Key, typename Data, typename Compare >
	inline void Deserialize(std::multimap< Key, Data, Compare >& obj);
	inline void Deserialize(std::string& obj);

	/// Custom type
	inline void Deserialize(ISerializable& obj);

	/// Pointer type
	template< typename T >
	inline void Deserialize(T* objPtr);

private : //! @name Data
	//! @{
	std::ostream* _os;
	std::istream* _is;
	//! @}
};

class ISerializable
{
public:

	virtual std::string getSignature() const = 0;
	virtual void serialize(ISerializer* serializer) const = 0;
	virtual void deserialize(ISerializer* serializer) = 0;
};

	}
}

#	include "serializer.inl"

#endif // !DW_SYSTEM_SERIALIZER_H
